%==========================================================================
%   This function simulates MF card response in 2nd step of authorization.
%
%   Written by: Shan Song
%   Date: Sept 15, 2010
%==========================================================================
%
%function inputs:
%   key:    Secret key that is loaded into LFSR. 64bit unsigned int
%   uid:    Card ID. 32bit unsigned int.
%   nt:     Card challendge. 32bit unsigned int.
%   nr_ks1: reader response, first part, nr^ks1. 32bit unsigned int.
%   nr_ks2: reader response, second part, suc2(nt)^ks2. 32bit unsigned int.
%
%function outputs:
%   ks1:    32-bit keystream that xor with nR.32bit unsigned int.
%   ks2:    32-bit keystream that xor with suc2(nT).32bit unsigned int.
%   ks3:    4-bit keystream that xor with NACK.32bit unsigned int.
%   state1: LFSR state after ks1 is generated. 64bit unsigned int.
%   state2: LFSR state after ks2 is generated. 64bit unsigned int.
%   state3: final LFSR state after ks3 is generated. 64bit unsigned int.
%	ks_pb:	8 parity bits calculated with nr^ks1 and suc2(nt)^ks2
%
function [ks1, ks2, ks3, state1, state2, state3, ks_pb] = MFCard(key, uid, nt, nr_ks1, suc_ks2)

[ks0, state0] = CRYPTO1_32(key, bitxor(uid,nt), uint32(1)); %linear feedback
[ks1, state1] = CRYPTO1_32(state0, nr_ks1, uint32(3)); %non-linear feedback to decode nr and feed nr into LFSR
[ks2, state2] = CRYPTO1_32(state1, nr_ks1*0, uint32(1));
[ks3, state3] = CRYPTO1_4(state2, nr_ks1*0, uint32(1));  %linear feedback

%calculate the encrypted odd-parity values

%get 8bits of keystream
ks = bitand(ks3,uint32(1)) + ...
bitand(ks2,uint32(1))*uint32(2) + ...
bitand(bitshift(ks2,-8),uint32(1))*uint32(4)+...
bitand(bitshift(ks2,-16),uint32(1))*uint32(8)+...
bitand(bitshift(ks2,-24),uint32(1))*uint32(16)+...
bitand(ks1,uint32(1))*uint32(32)+...
bitand(bitshift(ks1,-8),uint32(1))*uint32(64)+...
bitand(bitshift(ks1,-16),uint32(1))*uint32(128);

%calculate original nr and suc2nT
nr = bitxor(nr_ks1, ks1);
suc = bitxor(suc_ks2, ks2);

%get 8 parity bits from nr and suc
nr_bytes = bitand(bitshift(nr(1), [-24:8:0]),uint32(255*ones(1,4)));
suc_bytes = bitand(bitshift(suc(1), [-24:8:0]),uint32(255*ones(1,4)));


nr_parity = bitand( bitand(bitshift(nr_bytes,0),uint32(ones(1,4)))+...
                    bitand(bitshift(nr_bytes,-1),uint32(ones(1,4)))+...
                    bitand(bitshift(nr_bytes,-2),uint32(ones(1,4)))+...
                    bitand(bitshift(nr_bytes,-3),uint32(ones(1,4)))+...
                    bitand(bitshift(nr_bytes,-4),uint32(ones(1,4)))+...
                    bitand(bitshift(nr_bytes,-5),uint32(ones(1,4)))+...
                    bitand(bitshift(nr_bytes,-6),uint32(ones(1,4)))+...
                    bitand(bitshift(nr_bytes,-7),uint32(ones(1,4)))+...
                    uint32(ones(1,4)), ...
                    uint32(ones(1,4)));

suc_parity = bitand( bitand(bitshift(suc_bytes,0),uint32(ones(1,4)))+...
                    bitand(bitshift(suc_bytes,-1),uint32(ones(1,4)))+...
                    bitand(bitshift(suc_bytes,-2),uint32(ones(1,4)))+...
                    bitand(bitshift(suc_bytes,-3),uint32(ones(1,4)))+...
                    bitand(bitshift(suc_bytes,-4),uint32(ones(1,4)))+...
                    bitand(bitshift(suc_bytes,-5),uint32(ones(1,4)))+...
                    bitand(bitshift(suc_bytes,-6),uint32(ones(1,4)))+...
                    bitand(bitshift(suc_bytes,-7),uint32(ones(1,4)))+...
                    uint32(ones(1,4)), ...
                    uint32(ones(1,4)));
pb = (nr_parity(1)*uint32(8)+nr_parity(2)*uint32(4)+nr_parity(3)*uint32(2)+nr_parity(4)*uint32(1))*uint32(16)+...
suc_parity(1)*uint32(8)+suc_parity(2)*uint32(4)+suc_parity(3)*uint32(2)+suc_parity(4)*uint32(1);

ks_pb = uint8(bitxor(ks(1), pb));